/*
 * -------------------------------------------------------------------------
 * package.scripts 脚本命令管理
 * -------------------------------------------------------------------------
 * 此脚本管理package.scripts中的命令
 * 此脚本因在node环境下执行，无法使用electron
 */
const os    = require('os');
const fs    = require('fs');
const path  = require('path');
const spawn = require('child_process').spawn;
const _     = require('lodash');
const file  = require('./helper/file/noLog');
const arch  = require('./helper/arch');
const is    = require('./helper/is');

/*获取命令标识*/
const cmd = process.argv[2];

/*实例化助手类*/
const Helper = new Helpers();

/*更新 package.json 的name，解决32、64位识别为同一程序问题*/
Helper.updatePackage();

/*获取更新后的 package 配置*/
const packageJson = require('./package.json');

/**
 * 全部命令
 * @type {{'compile:setup': string, '$wait:dev:vue': string, 'dev:vue': string, 'dev:electron': string, 'build:electron': string, 'build:all': string, 'build:vue': string, __buildElectron: Helpers.buildElectron, __compileSetup: Helpers.compileSetup, __clearFiles: Helpers.clearFiles, oneKey: string}}
 */
const cmds = {
    /**
     * 调试 vue
     */
    'dev:vue': `cd app-vue && npm run dev`,
    
    /**
     * 调试 electron
     */
    'dev:electron': `electron .`,
    
    /**
     * 编译 vue
     */
    'build:vue': `cd app-vue && npm run build`,
    
    /**
     * 打包 electron
     */
    'build:electron': `node package-scripts.js __buildElectron && node package-scripts.js __copyPlugins`,
    
    /**
     * 完整项目打包（编译vue && 打包electron应用 && 清理打包目录的无用文件）
     */
    'build:all': `npm run build:vue && npm run build:electron && node package-scripts.js __clearFiles`,
    
    /**
     * 编译安装包
     */
    'compile:setup': `node package-scripts.js __compileSetup`,
    
    /**
     * 一键编译安装包
     */
    'oneKey': `npm run build:all && npm run compile:setup`,
    
    /**
     * 隐藏命令：等待vue调试环境启动成功后，启动electron调试环境
     */
    '$wait:dev:vue': `wait-on http-get://${packageJson.configs.develop.host}:${packageJson.configs.develop.port} && npm run dev:electron`,
    
    /**
     * 辅助方法：打包 electron
     */
    '__buildElectron': Helper.buildElectron,
    
    /**
     * 辅助方法：清理文件
     */
    '__clearFiles': Helper.clearFiles,
    
    /**
     * 辅助方法：复制插件
     */
    '__copyPlugins': Helper.copyPlugins,
    
    /**
     * 辅助方法：编译安装包
     */
    '__compileSetup': Helper.compileSetup
};

/*命令不存在*/
if (!cmds[cmd]) {
    console.log(`[ERROR] 命令不存在 [${cmd}]`);
    process.exit();
}

/*辅助方法调用*/
if (cmd.substring(0, 2) === '__' && is.func(cmds[cmd])) {
    cmds[cmd]();
}
/*执行命令*/
else {
    Helper.runProgram(is.func(cmds[cmd]) ? cmds[cmd]() : cmds[cmd]);
}

/**
 * 助手类
 * @constructor
 */
function Helpers () {
    /**
     * 打包 electron
     */
    this.buildElectron = () => {
        /*提示*/
        console.log('[INFO] ->', '-------------------------');
        console.log('[INFO] ->', '打包 electron');
        console.log('[INFO] ->', '-------------------------');
        
        let configs  = packageJson.configs;
        let packager = require('electron-packager');
        packager({
            name           : packageJson.appName,
            appVersion     : packageJson.version,
            icon           : configs.icon.normal,
            platform       : configs.electron.platform,
            arch           : arch.getArch(),
            buildVersion   : packageJson.version,
            out            : configs.electron.out,
            electronVersion: configs.electron.version,
            executableName : packageJson.appName,
            asar           : configs.electron.asar,
            overwrite      : true,
            prune          : true,
            appCopyright   : configs.appCopyright,
            dir            : '.',
            ignore         : [
                '^/.git',
                '^/.idea',
                '^/.ignore',
                '^/.gitignore',
                '^/__doc',
                '^/app-vue',
                '^/setup',
                '^/plugins',
                `^/${configs.production.tempDir}`,
                `^/${configs.inno.out}`,
                `^/${configs.electron.out}`,
                '^/package-scripts.js',
                '^/setup/release-licence-gbk.txt',
                '^/readme.md',
                '.psd$'
            ],
            win32metadata  : {
                CompanyName     : configs.companyName,
                FileDescription : packageJson.description,
                OriginalFilename: `${packageJson.appName}.exe`,
                ProductName     : packageJson.appName,
                InternalName    : packageJson.appName,
                
                /* asInvoker | highestAvailable | requireAdministrator */
                'requested-execution-level': configs.electron.requireAdministrator ? 'requireAdministrator' : 'asInvoker'
            }
        }).then((path) => {
            console.log('[INFO] Electron Packager 打包成功！');
            console.log(`[INFO] Out path: ${path}`);
        }).catch((err) => {
            console.log('[ERROR] Electron Packager 打包失败：');
            console.log(err);
        });
    };
    
    /**
     * 清理文件
     */
    this.clearFiles = () => {
        /*提示*/
        console.log('[INFO] ->', '-------------------------');
        console.log('[INFO] ->', '清理 electron 文件');
        console.log('[INFO] ->', '-------------------------');
        
        /*清理文件列表*/
        let files = [];
        
        /*语言*/
        let languages = [
            'am', 'ar', 'bg', 'bn', 'ca', 'cs', 'da', 'de', 'el', 'es',
            'et', 'fa', 'fi', 'fr', 'gu', 'he', 'hi', 'hr', 'hu', 'id',
            'it', 'ja', 'kn', 'ko', 'lt', 'lv', 'ml', 'mr', 'ms', 'nb',
            'nl', 'pl', 'ro', 'ru', 'sk', 'sl', 'sr', 'sv', 'sw', 'ta',
            'te', 'th', 'tr', 'uk', 'vi', 'fil', 'en-GB', 'en-US', 'pt-BR', 'pt-PT',
            'zh-TW', 'es-419'
        ];
        for (let i = 0; i < languages.length; i++) {
            files.push(`locales/${languages[i]}.pak`);
        }
        
        /*其他文件*/
        files.push('LICENSE');
        files.push('LICENSES.chromium.html');
        files.push('version');
        
        for (const key in files) file.delFiles(path.resolve(this.getElectronBuildDir(), files[key]));
    };
    
    /**
     * 复制插件目录到打包目录
     */
    this.copyPlugins = () => {
        /*提示*/
        console.log('[INFO] ->', '-------------------------');
        console.log('[INFO] ->', '复制插件目录');
        console.log('[INFO] ->', '-------------------------');
        
        let source = path.resolve(__dirname, 'plugins');
        let target = path.resolve(__dirname, `${this.getElectronBuildDir()}/plugins`);
        file.copyFiles(source, target);
    };
    
    /**
     * 编译安装包
     */
    this.compileSetup = () => {
        /*提示*/
        console.log('[INFO] ->', '-------------------------');
        console.log('[INFO] ->', '编译 Inno 安装包');
        console.log('[INFO] ->', '-------------------------');
        
        let configs = packageJson.configs;
        let tpl     = fs.readFileSync(path.resolve(__dirname, 'setup/inno/tpl.iss'), 'utf8');
        
        /*模板变量*/
        let tags = {
            CusAppId       : this.getInnoAppid(),
            CusAppName     : packageJson.appName,
            CusAppVersion  : packageJson.version,
            CusAppPublisher: packageJson.author,
            CusArchFlag    : arch.getArch(),
            CusAppURL      : configs.website,
            CusAppIcon     : path.resolve(__dirname, configs.icon.normal),
            CusProjectPath : path.resolve(__dirname),
            CusResourceDir : path.resolve(__dirname, configs.electron.out),
            CusOutDir      : path.resolve(__dirname, configs.inno.out)
        };
        
        /*替换变量*/
        for (const k in tags) {
            tpl = tpl.replace(new RegExp('\\{\\$' + k + '\\}', 'g'), tags[k]);
        }
        
        /*生成inno配置文件*/
        let iconv   = require('iconv-lite');
        let encoded = iconv.encode(tpl, 'gbk');
        let iss     = path.resolve(__dirname, configs.production.tempDir, `compile-setup-inno-${arch.getArch()}.iss`);
        
        /*尝试创建目录*/
        file.mkdir(path.dirname(iss));
        
        /*更新文件*/
        fs.writeFileSync(iss, encoded);
        
        /*编译安装包*/
        this.runProgram({
            program: configs.inno.iscc,
            args   : [iss]
        });
    };
    
    /**
     * 执行程序
     * @param cmd
     */
    this.runProgram = (cmd) => {
        /*打印命令*/
        console.log('[INFO] ->', '--- run -----------------');
        console.log('[INFO] ->', cmd);
        console.log('[INFO] ->', '-------------------------');
        
        /*执行命令*/
        let ps;
        
        /*执行自定义程序*/
        if (is.obj(cmd)) {
            ps = spawn(cmd.program, cmd.args);
        }
        
        /*执行cmd程序*/
        else {
            ps = spawn('cmd.exe', ['/s', '/c', `chcp 65001 && ${cmd}`]);
        }
        
        /*捕获标准输出并将其打印到控制台*/
        ps.stdout.on('data', data => console.log(_.trim(data.toString())));
        
        /*捕获标准错误输出并将其打印到控制台*/
        ps.stderr.on('data', data => console.log(_.trim(data.toString())));
        
        /*注册子进程关闭事件*/
        ps.on('exit', (code, signal) => (code && console.log(`${os.EOL}[Abnormal exit]`, code, signal || '')));
    };
    
    /**
     * 获取electron发布目录
     * @return {string}
     */
    this.getElectronBuildDir = () => {
        let electron = packageJson.configs.electron;
        return path.resolve(__dirname, `${electron.out}/${packageJson.appName}-${electron.platform}-${arch.getArch()}`);
    };
    
    /**
     * 获取inno appid
     * @returns {string}
     */
    this.getInnoAppid = () => arch.archIsX64() ? packageJson.configs.inno.appId.x64 : packageJson.configs.inno.appId.ia32;
    
    /**
     * 更新 package.json
     */
    this.updatePackage = () => {
        let packageFile = path.resolve(__dirname, 'package.json');
        let packageStr  = fs.readFileSync(packageFile, 'utf8').toString();
        let packageObj  = JSON.parse(packageStr);
        
        /*更新 package.name*/
        packageStr = packageStr.replace(/(\"name\")(.*?):(.*?)\"(.*?)\"(.*?),/, `$1$2:$3"${packageObj.appName}-${arch.getArch()}",`);
        
        /*更新文件*/
        fs.writeFileSync(packageFile, packageStr, 'utf8');
    };
}
